%%*****************************************************************
%% HSDsqlpcheckconvg: check convergence.
%%
%% ZpATynorm, AX, normX, normZ are with respect to the 
%% original variables, not the HSD variables. 
%%*****************************************************************
%% SDPT3: version 4.0
%% Copyright (c) 1997 by
%% Kim-Chuan Toh, Michael J. Todd, Reha H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************

  function [param,breakyes,use_olditer,msg] = HSDsqlpcheckconvg(param,runhist)

      termcode    = param.termcode; 
      iter        = param.iter; 
      obj         = param.obj;
      relgap      = param.relgap; 
      gap         = param.gap; 
      prim_infeas = param.prim_infeas;
      dual_infeas = param.dual_infeas; 
      mu          = param.mu;  
      prim_infeas_bad = param.prim_infeas_bad; 
      dual_infeas_bad = param.dual_infeas_bad; 
      printlevel  = param.printlevel;
      stoplevel   = param.stoplevel; 
      inftol      = param.inftol; 
      gaptol      = param.gaptol;
      kap         = param.kap; 
      tau         = param.tau;       
      theta       = param.theta; 
      breakyes    = 0; 
      use_olditer = 0; 
      msg         = [];
      infeas      = max(prim_infeas,dual_infeas); 
      prim_infeas_min = min(param.prim_infeas_min, max(prim_infeas,1e-10));  
      dual_infeas_min = min(param.dual_infeas_min, max(dual_infeas,1e-10)); 
%%
      err = max(infeas,relgap); 
      if (obj(2) > 0); homRd = param.ZpATynorm/obj(2); else; homRd = inf; end
      if (obj(1) < 0); homrp = norm(param.AX)/(-obj(1)); else; homrp = inf; end
      if (param.normX > 1e15*max(1,param.normX0)) | (param.normZ > 1e15*max(1,param.normZ0))
         termcode = 3;
         breakyes = 1; 
      end
      if (homRd < min(1e-6,1e-2*sqrt(err*inftol)) & (tau < 1e-4) ...
          & prim_infeas > 0.5*runhist.pinfeas(iter)) ...
         | (homRd < 10*tau & tau < 1e-7)
         termcode = 1;
         breakyes = 1;
      end
      if (homrp < min(1e-6,1e-2*sqrt(err*inftol)) & (tau < 1e-4) ...
         & dual_infeas > 0.5*runhist.dinfeas(iter)) ...
         | (homrp < 10*tau & tau < 1e-7)
         termcode = 2;
         breakyes = 1;
      end
      if (err < gaptol)
         msg = sprintf('Stop: max(relative gap,infeasibilities) < %3.2e',gaptol);
         if (printlevel); fprintf('\n  %s',msg); end
         termcode = 0;
         breakyes = 1;
      end
      min_prim_infeas = min(runhist.pinfeas(1:iter)); 
      prim_infeas_bad = prim_infeas_bad + (prim_infeas > ...
           max(1e-10,5*min_prim_infeas) & (min_prim_infeas < 1e-2));
      if (mu < 1e-6)
         idx = [max(1,iter-1): iter];
      elseif (mu < 1e-3);
         idx = [max(1,iter-2): iter]; 
      else
         idx = [max(1,iter-3): iter];
      end
      idx2 = [max(1,iter-4): iter]; 
      gap_ratio2 = runhist.gap(idx2+1)./runhist.gap(idx2);
      gap_slowrate = min(0.8,max(0.6,2*mean(gap_ratio2)));
      gap_ratio = runhist.gap(idx+1)./runhist.gap(idx);
      pstep = runhist.step(iter+1);  
      if (infeas < 1e-4 | prim_infeas_bad) & (relgap < 1e-3) ...
         & (iter > 5) & (prim_infeas > (1-pstep/2)*runhist.pinfeas(iter)) 
         gap_slow = all(gap_ratio > gap_slowrate) & (relgap < 1e-3);
         min_pinfeas = min(runhist.pinfeas); 
         if (relgap < 0.1*infeas) ...
	    & ((runhist.step(iter+1) < 0.5) | (min_pinfeas < min(1e-6,0.1*prim_infeas))) ...
            & (dual_infeas > 0.9*runhist.dinfeas(iter) | (dual_infeas < 1e-2*gaptol))
            msg = 'Stop: relative gap < infeasibility'; 
            if (printlevel); fprintf('\n  %s',msg); end
            termcode = -1;
            breakyes = 1;           
         elseif (gap_slow) & (infeas > 0.9*runhist.infeas(iter)) ...
            & (theta < 1e-8)
            msg = 'Stop: progress is too slow'; 
            if (printlevel); fprintf('\n  %s',msg); end
            termcode = -5; 
            breakyes = 1;
         end  
      elseif (prim_infeas_bad) & (iter >50) & all(gap_ratio > gap_slowrate)
         msg = 'Stop: progress is bad';
         if (printlevel); fprintf('\n  %s',msg); end
         termcode = -5;
         breakyes = 1; 
      elseif (infeas < 1e-8) & (gap > 1.2*mean(runhist.gap(idx)))
         msg = 'Stop: progress is bad*'; 
         if (printlevel); fprintf('\n  %s',msg); end
         termcode = -5;
         breakyes = 1;  
      end
      if (err < 1e-3) & (iter > 10) ...
         & (runhist.pinfeas(iter+1) > 0.9*runhist.pinfeas(max(1,iter-5))) ...
         & (runhist.dinfeas(iter+1) > 0.9*runhist.dinfeas(max(1,iter-5))) ...
         & (runhist.relgap(iter+1)  > 0.1*runhist.relgap(max(1,iter-5))); 
         msg = 'Stop: progress is bad**';
         if (printlevel); fprintf('\n  %s',msg); end
         termcode = -5;
         breakyes = 1;  
      end
      if (infeas > 100*max(1e-12,min(runhist.infeas)) & relgap < 1e-4)
         msg = 'Stop: infeas has deteriorated too much'; 
         if (printlevel); fprintf('\n  %s, %3.1e',msg,infeas); end
         use_olditer = 1; 
         termcode = -7; 
         breakyes = 1; 
      end
      if (min(runhist.infeas) < 1e-4 | prim_infeas_bad) ...
         & (max(runhist.infeas) > 1e-4) & (iter > 5)
         relgap2 = abs(diff(obj))/(1+mean(abs(obj))); 
         if (relgap2 < 1e-3); 
            step_short = all(runhist.step([iter:iter+1]) < 0.1) ;
         elseif (relgap2 < 1) 
            idx = [max(1,iter-3): iter+1];
            step_short = all(runhist.step(idx) < 0.05); 
         else
            step_short = 0; 
         end
         if (step_short) 
            msg = 'Stop: steps too short consecutively'; 
            if (printlevel); fprintf('\n  %s',msg); end
            termcode = -5; 
            breakyes = 1;      
         end
      end
      if (iter > 3 & iter < 20) & (max(runhist.step(max(1,iter-3):iter+1)) < 1e-3) ...
         & (infeas > 1) & (min(homrp,homRd) > 1000*inftol) 
         if (stoplevel >= 2)
            msg = 'Stop: steps too short consecutively'; 
            if (printlevel); fprintf('\n  %s',msg); end
            termcode = -5;
            breakyes = 1;              
         end
      end
      if (pstep < 1e-4) & (err > 1.1*max(runhist.relgap(iter),runhist.infeas(iter)))
         msg = 'Stop: steps are too short';
         if (printlevel); fprintf('\n  %s',msg); end
         use_olditer = 1; 
         termcode = -5; 
         breakyes = 1; 
      end
      if (iter == param.maxit) 
         termcode = -6; 
         msg = 'Stop: maximum number of iterations reached'; 
         if (printlevel); fprintf('\n  %s',msg); end
      end
      if (infeas < 1e-8 & relgap < 1e-10 & kap < 1e-13 & theta < 1e-15)
         msg = 'Stop: obtained accurate solution';
         if (printlevel); fprintf('\n  %s',msg); end
         termcode = 0; 
         breakyes = 1;          
      end
      param.prim_infeas_bad = prim_infeas_bad;
      param.prim_infeas_min = prim_infeas_min;
      param.dual_infeas_bad = dual_infeas_bad;
      param.dual_infeas_min = dual_infeas_min;
      param.termcode = termcode;
%%*****************************************************************************
